//***************************************************************************
//   Copyright(c)2022, Xidian University D405.
//   All rights reserved
//
//   IP Name         :   Null
//   File name       :   cpu_ahb_np_top.v
//   Module name     :   cpu_ahb_np_top
//   Author          :   Zhang-Jianyuan
//   Date            :   2022/07/02
//   Version         :   v1.2
//   Verison History :   v1.0/v1.1/v1.2
//   Edited by       :   Wang Zekun
//   Modification history : v1.0 Initial revision
//                          v1.1 modify compile error
//                          v1.2 add read phy access ack
// ----------------------------------------------------------------------------
// Version 1.20      Date(2022/07/02)
// Abstract :   ahb signals convert to np inside data
//
//-----------------------------------------------------------------------------
// Programmer's model
// Base Address 0x0BE0_0000---0x0BEF_FFFF
//
//-----------------------------------------------------------------------------
//interface list :
//                AHB

module cpu_ahb_np_top(
     input  wire         clk_sys
    ,input  wire         rst_n_sys
    // AHB BUS
    ,input  wire         HRESETn
    ,input  wire         HCLK   
    ,input  wire         HSEL   
    ,input  wire [31:0]  HADDR  
    ,input  wire [ 1:0]  HTRANS 
    ,input  wire [ 2:0]  HSIZE  
    ,input  wire [ 2:0]  HBURST 
    ,input  wire [ 3:0]  HPROT  
    ,input  wire         HWRITE 
    ,input  wire [31:0]  HWDATA 
    ,input  wire         HREADYin
    ,output reg  [31:0]  HRDATA 
    ,output reg          HREADYout
    ,output reg          HRESP  
    // scan
    ,input  wire         scan_mode
    ,input  wire         scan_set_rst
    // phy read
    ,input  wire         phy_rd_process
    ,input  wire         phy_rd_ack
    // with np
    ,output wire [31:0]  np_addr_in 
    ,output wire [31:0]  np_data_in 
    ,output wire         np_wr      
    ,output wire         np_rd      
    ,input  wire [31:0]  np_data_out
);

wire [31:0] HRDATA_OUT     ;
//=====================================================
wire Hvld;
wire HRDy;
assign Hvld = HSEL & HTRANS[1];
assign HRDy = Hvld & HREADYin;
wire        HACK           ;
//=====================================================
//write
reg [31:0] HADDR_d1;
reg HWR_vld_d1;
reg HRD_vld_d1;
always @(posedge HCLK or negedge HRESETn) begin
    if(~HRESETn)begin
        HADDR_d1 <= 32'h0;
        HWR_vld_d1 <= 1'b0;
        HRD_vld_d1 <= 1'b0;
    end else if(HREADYin)begin
        HADDR_d1 <= {13'h0,HADDR};
        HWR_vld_d1 <= Hvld & HWRITE ;
        HRD_vld_d1 <= Hvld & !HWRITE;
    end 
end
//-----------------------------------------------------
reg HWR,HRD;
wire HWR_pulse, HRD_pulse;
reg [31:0]HADDR_IN;
reg [31:0]HWDATA_IN;
reg HWR_IN,HRD_IN;
always @(posedge HCLK or negedge HRESETn) begin
    if(~HRESETn)begin
        HWR <= 1'b0;
        HRD <= 1'b0;
    end else begin
        HWR <= HWR_vld_d1;
        HRD <= HRD_vld_d1;
    end
end

assign HWR_pulse = HWR_vld_d1 & !HWR;
assign HRD_pulse = HRD_vld_d1 & !HRD;

always @(posedge HCLK or negedge HRESETn) begin
    if(~HRESETn)
        HADDR_IN <= 32'b0;
    else if(HWR_pulse | HRD_pulse)
        HADDR_IN <= HADDR_d1;
end

always @(posedge HCLK or negedge HRESETn) begin
    if(~HRESETn)
        HWDATA_IN <= 32'b0;
    else if(HWR_pulse)
        HWDATA_IN <= HWDATA;
end

always @(posedge HCLK or negedge HRESETn) begin
    if(~HRESETn)begin
        HWR_IN <= 1'b0;
        HRD_IN <= 1'b0;
    end else begin
        HWR_IN <= HWR_pulse & !HACK;
        HRD_IN <= HRD_pulse & !HACK;
    end
end


//=====================================================
// read
always @(posedge HCLK or negedge HRESETn) begin
    if(~HRESETn)
        HRESP <= 2'b0;
    else
        HRESP <= HRESP ;
end

// always @(posedge HCLK or negedge HRESETn) begin
//     if(~HRESETn)
//         HREADYout <= 1'b1;
//     else if(HRDy)
//         if(HWRITE)
//             HREADYout <= 1'b1;//write
//         else
//             HREADYout <= 1'b0;//read
//     else if(HRD_vld_d1 && HACK)//rd_ack
//         HREADYout <= 1'b1;
// end
//liuyu 6.13
always @(posedge HCLK or negedge HRESETn) begin
    if(~HRESETn)
        HREADYout <= 1'b1;
    else if(HRDy)
        HREADYout <= 1'b0;
    else if(phy_rd_process)
        HREADYout <= phy_rd_ack;
    else if((HRD_vld_d1 && HACK)||(HWR_vld_d1 && HACK))//rd_ack & wr_ack
        HREADYout <= 1'b1;
end

always @(posedge HCLK or negedge HRESETn) begin
    if(~HRESETn)
        HRDATA <= 32'h0;
    else if (phy_rd_process)
        HRDATA <= np_data_out;
    else if (HRD_vld_d1 && HACK)//rd_ack
        HRDATA <= HRDATA_OUT;
end





























 wire [31:0] cpu_addr_in    ;
 wire [31:0] cpu_data_in    ;
 wire        cpu_wr         ;
 wire        cpu_rd         ;
 wire        cpu_ack        ;
 wire [31:0] cpu_data_out   ;



// reg       HSEL_IN;
// reg       HSEL_ff;
// reg  [31:0] HADDR_ff       ;
// reg  [31:0] HADDR_IN       ;
// reg  [31:0] HWDATA_IN      ;
// reg         HWR         ;
// reg         HRD         ;
// reg         HWR_ff         ;
// reg         HRD_ff         ;
// reg         HWR_IN         ;
// reg         HRD_IN         ;


// wire [31:0] cpu_addr_in    ;
// wire [31:0] cpu_data_in    ;
// wire        cpu_wr         ;
// wire        cpu_rd         ;
// wire        cpu_ack        ;
// wire [31:0] cpu_data_out   ;




// always@(posedge HCLK or negedge HRESETn) begin
//     if(!HRESETn)
//         HSEL_IN <= 0;
//     else if (HSEL) 
//         HSEL_IN <= 1;
//     else if(HACK)
// 	HSEL_IN <= 0;
//     else 
// 	HSEL_IN <= HSEL_IN;
// end

// always@(*) begin
	
//     		HWDATA_IN = HWDATA;
    
// end

// always@(posedge HCLK or negedge HRESETn)begin
// 	if(~HRESETn)begin
// 		HSEL_ff <= 0;
// 		HADDR_ff <= 0;
// 	end else begin
// 		HADDR_ff <= HADDR;
// 		HSEL_ff <= HSEL;
// 	end
// end
// always @(*)begin
//     if(HSEL_ff)
//     	HADDR_IN = HADDR_ff;
//     else if(HSEL)
// 	    HADDR_IN = HADDR;
//     else 
// 	HADDR_IN = 32'b0;
// end

// always@(*) begin
//   	if({HSEL,HWRITE} == 2'b11)begin
// 		case(HTRANS)
// 			2'b10,
// 			2'b11:begin
// 				HWR = 1;
//     			HRD = 0;
// 			end
// 			default:begin
// 	    		HWR = 0;
//     			HRD = 0;
// 			end
// 		endcase
//   	end else if({HSEL,HWRITE} == 2'b10)begin
//     		case(HTRANS)
// 			2'b10,
// 			2'b11:begin
// 				HWR = 0;
//     			HRD = 1;
// 			end
// 			default:begin
// 	    		HWR = 0;
//     			HRD = 0;
// 			end
// 		endcase
//   	end else begin
//     		HWR = 0;
//     		HRD = 0;
// 	end
// end
// always@(posedge HCLK or negedge HRESETn)begin
// 	if(~HRESETn)begin
// 		HWR_ff <= 1'b0;
//         HRD_ff <= 1'b0;
// 	end else begin
// 		HWR_ff <= HWR;
//         HRD_ff <= HRD;
// 	end
// end
// always@(*)begin
//     if(HSEL_ff)
// 	    HRD_IN = HRD_ff;
//     else if(HSEL)
//         HRD_IN = HRD;
//     else
//         HRD_IN = 1'b0;
// end

// always @(*)begin
//     if(HSEL_ff)
//     	HWR_IN = HWR_ff;
//     else if(HSEL)
// 	    HWR_IN = HWR;
//     else 
// 	    HWR_IN = 1'b0;
// end

// always @(*)begin
//     if(HSEL || HSEL_IN )//write
//         HREADY = 0;
//     else
//         HREADY = 1;
// end

// //assign HRESP = 0;		
// assign HRDATA = HRDATA_OUT;

np_cfg_cdc_ctl cfg_cdc_ctl (
    // CFG External Clock and reset
    .cfg_ext_clk            (HCLK           ),
    .cfg_ext_clk_rst        (~HRESETn       ),

    // Clock and reset
    .cfg_clk                (clk_sys        ),
    .cfg_rst                (~rst_n_sys      ),

    // External CFG control bus
    .cfg_ext_addr           (HADDR_IN       ),
    .cfg_ext_wr_data        (HWDATA_IN      ),
    .cfg_ext_wr_en          (HWR_IN         ),
    .cfg_ext_rd_en          (HRD_IN         ),
    .cfg_ext_rd_data        (HRDATA_OUT     ),
    .cfg_ext_ack            (HACK           ),
    
    //scan
    .scan_mode              (scan_mode      ),
    .scan_set_rst           (scan_set_rst   ),
  
    // CFG control bus 
    .cfg_addr               (cpu_addr_in    ),
    .cfg_wr_data            (cpu_data_in    ),
    .cfg_wr_en              (cpu_wr         ),
    .cfg_rd_en              (cpu_rd         ),
    .cfg_ack                (cpu_ack        ),
    .cfg_rd_data            (cpu_data_out   )
);

np_access_det access_det (
  // CFG Clock and Reset
  .cfg_clk          (clk_sys        ),
  .cfg_rst          (~rst_n_sys     ),

  // CFG input interfaces
  .cfg_addr         (cpu_addr_in    ),
  .cfg_wr_data      (cpu_data_in    ),
  .cfg_wr_en        (cpu_wr         ),
  .cfg_rd_en        (cpu_rd         ),
  .cfg_ack          (cpu_ack        ),
  .cfg_rd_data      (cpu_data_out   ),

  // CFG output interface
  .cfg_addr_o       (np_addr_in     ),
  .cfg_wr_data_o    (np_data_in     ),
  .cfg_wr_en_o      (np_wr          ),
  .cfg_rd_en_o      (np_rd          ),
  .cfg_rd_data_i    (np_data_out    )
);


endmodule
